#pragma once
#include <iostream>
#include <queue>

static const int defaultcap = 5;

template <class T>
class BlockQueue
{
private:
    bool isFull()
    {
        return _max_cap == _block_queue.size();
    }
    bool isEmpty()
    {
        return _block_queue.size() == 0;
    }

public:
    BlockQueue(int max_cap = defaultcap)
        : _max_cap(max_cap), _low_water(_max_cap / 3), _high_water(_max_cap / 3 * 2)
    {
        pthread_mutex_init(&_mutex, nullptr);
        pthread_cond_init(&_c_cond, nullptr);
        pthread_cond_init(&_p_cond, nullptr);
    }
    void Pop(T *out)
    {
        pthread_mutex_lock(&_mutex);

        while (isEmpty())
        {
            pthread_cond_wait(&_c_cond, &_mutex); // 排队同步
        }
        //std::cout << _block_queue.size() << std::endl;
        *out = _block_queue.front();
        //std::cout << *out << std::endl;
        _block_queue.pop();
        // if (_block_queue.size() < _low_water)
        //     pthread_cond_signal(&_p_cond); // 唤醒生产者
        pthread_cond_signal(&_p_cond);
        pthread_mutex_unlock(&_mutex);
    }
    void Enqueue(T *in)
    {
        pthread_mutex_lock(&_mutex);

        while (isFull())
        {
            pthread_cond_wait(&_p_cond, &_mutex); // 排队同步
        }
        _block_queue.push(*in);
        // if (_block_queue.size() > _high_water)
        //     pthread_cond_signal(&_c_cond); // 唤醒消费者
        pthread_cond_signal(&_c_cond);
        pthread_mutex_unlock(&_mutex);
    }
    ~BlockQueue()
    {
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_c_cond);
        pthread_cond_destroy(&_p_cond);
    }

private:
    std::queue<T> _block_queue;
    int _max_cap;
    pthread_cond_t _p_cond;
    pthread_cond_t _c_cond;
    pthread_mutex_t _mutex;
    int _low_water; // 低水平线
    int _high_water;
};